package com.dddpeter.app.config;

import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.dddpeter.app.entity.Article;
import com.dddpeter.app.entity.User;
import com.dddpeter.app.service.IdGeneratorService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 自定义ID生成器
 * 生成12位数字的ID，范围：100000000000 - 999999999999
 * 确保ID的唯一性，避免重复
 */
@Component
public class CustomIdGenerator implements IdentifierGenerator {
    
    @Autowired
    @Lazy
    private IdGeneratorService idGeneratorService;
    
    // 用于记录当前序列号，避免同一毫秒内重复
    private final AtomicInteger sequence = new AtomicInteger(0);
    private long lastTimestamp = -1L;
    
    // 实例ID，用于区分不同服务实例（可以通过配置设置）
    private final int instanceId = 1; // 可以从配置文件读取
    
    // 最大重试次数，避免无限循环
    private static final int MAX_RETRY = 10;
    
    @Override
    public Number nextId(Object entity) {
        // 如果是Article或User实体，使用数据库确保唯一性
        if (entity instanceof Article) {
            return idGeneratorService.generateArticleId();
        } else if (entity instanceof User) {
            return idGeneratorService.generateUserId();
        }
        
        // 其他实体使用原有的时间戳算法
        synchronized (this) {
            for (int retry = 0; retry < MAX_RETRY; retry++) {
                long timestamp = System.currentTimeMillis();
                
                // 如果时间戳倒退（时钟调整），等待下一个毫秒
                if (timestamp < lastTimestamp) {
                    try {
                        Thread.sleep(1);
                        continue;
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        throw new RuntimeException("ID生成器被中断", e);
                    }
                }
                
                // 如果是新的毫秒，重置序列号
                if (timestamp != lastTimestamp) {
                    sequence.set(0);
                    lastTimestamp = timestamp;
                }
                
                // 获取当前序列号并递增
                int seq = sequence.getAndIncrement();
                
                // 如果序列号超过限制，等待下一个毫秒
                if (seq >= 10000) {
                    try {
                        Thread.sleep(1);
                        continue;
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        throw new RuntimeException("ID生成器被中断", e);
                    }
                }
                
                // 生成12位数字ID：
                // 时间戳后8位（10000000-99999999） + 实例ID（0-9） + 序列号（0-999）
                long timePart = (timestamp % 90000000L) + 10000000L; // 10000000-99999999
                int instancePart = instanceId % 10; // 0-9
                int seqPart = seq % 1000; // 0-999
                
                long id = timePart * 1000L + instancePart * 100L + seqPart;
                
                // 确保ID在12位数字范围内
                if (id < 100000000000L) {
                    id = 100000000000L + (id % 900000000000L);
                } else if (id > 999999999999L) {
                    id = 100000000000L + (id % 900000000000L);
                }
                
                // 验证ID的有效性
                if (isValidId(id)) {
                    return id;
                }
            }
            
            // 如果所有重试都失败，抛出异常
            throw new RuntimeException("无法生成唯一的ID，已达到最大重试次数");
        }
    }
    
    /**
     * 验证ID是否有效（12位数字）
     */
    private boolean isValidId(long id) {
        return id >= 100000000000L && id <= 999999999999L;
    }
    
    /**
     * 获取ID的组成部分（用于调试）
     */
    public String getIdComponents(long id) {
        long timePart = id / 1000;
        int instancePart = (int) ((id % 1000) / 100);
        int seqPart = (int) (id % 100);
        return String.format("时间戳部分: %d, 实例部分: %d, 序列号部分: %d", timePart, instancePart, seqPart);
    }
}

